﻿using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq.Expressions;

//将名称空间限定为System，从而解决引用问题
// ReSharper disable once CheckNamespace

namespace System.Linq
{
    public static class LinqExtension
    {
        /// <summary>
        /// 基于扩展方法的空检测
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="enumerator"></param>
        /// <returns></returns>
        public static bool IsNullOrEmpty<T>(this IEnumerable<T> enumerator)
        {
            return enumerator == null || !enumerator.Any();
        }

        /// <summary>
        /// 提供一个安全的投影
        /// </summary>
        /// <typeparam name="TIn"></typeparam>
        /// <typeparam name="TOut"></typeparam>
        /// <param name="enumerable"></param>
        /// <param name="mapper"></param>
        /// <returns></returns>
        public static IEnumerable<TOut> SelectOrDefault<TIn, TOut>(this IEnumerable<TIn> enumerable, Func<TIn, TOut> mapper)
        {
            Trace.Assert(enumerable != null);
            foreach (var @in in enumerable)
            {
                yield return mapper(@in);
            }
        }

        /// <summary>
        /// 使用连接符连接若干字符串
        /// </summary>
        /// <param name="enumerator"></param>
        /// <param name="separator"></param>
        /// <returns></returns>
        public static string Join(this IEnumerable<string> enumerator, string separator)
        {
            return string.Join(separator, enumerator);
        }

        /// <summary>
        /// 使用连接符连接若干字符串
        /// </summary>
        /// <param name="enumerator"></param>
        /// <param name="separator"></param>
        /// <returns></returns>
        public static string Join(this IEnumerable<string> enumerator, char separator)
        {
            return string.Join(separator + "", enumerator);
        }

        /// <summary>
        /// 使用连接符连接若干字符
        /// </summary>
        /// <param name="enumerator"></param>
        /// <param name="separator"></param>
        /// <returns></returns>
        public static string Join(this IEnumerable<char> enumerator, char separator)
        {
            return string.Join(separator + "", enumerator);
        }

        /// <summary>
        /// 使用连接符连接若干字符
        /// </summary>
        /// <param name="enumerator"></param>
        /// <param name="separator"></param>
        /// <returns></returns>
        public static string Join(this IEnumerable<char> enumerator, string separator) 
        {
            return string.Join(separator, enumerator);
        }

        /// <summary>
        /// 基于扩展的For-Each
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <param name="action"></param>
        public static void Foreach<T>(this IEnumerable<T> source, Action<T> action)
        {
            Trace.Assert(source != null);
            Trace.Assert(action != null);

            foreach (var item in source)
            {
                action(item);
            }
        }

        /// <summary>
        /// 基于扩展的For-Each
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <param name="action"></param>
        public static void Foreach<T>(this IEnumerable source, Action<T> action)
        {
            Trace.Assert(source != null);
            Trace.Assert(action != null);

            foreach (T item in source)
            {
                action(item);
            }
        }

        /// <summary>
        /// 基于参考序列的排序。给定一个已经排序好的集合，依次使用该集合中item作为测试元素，参考predicate进行匹配。
        /// 一旦匹配成功，则使用测试元素的排序值作为目标元素的排序值。
        /// 例如，对于abcdefg这个字符集合，使用gbc作为参考，同时使用char的equals作为测试表达式，那么结果就是gbcadef
        /// </summary>
        /// <typeparam name="TS"></typeparam>
        /// <typeparam name="TP"></typeparam>
        /// <param name="source"></param>
        /// <param name="sortedSource"></param>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public static IEnumerable<TS> OrderDepend<TS, TP>(this IEnumerable<TS> source,
            IEnumerable<TP> sortedSource, Func<TS, TP, bool> predicate)
        {
            var allItems = source.ToList();
            var temp = new List<TS>();
            foreach (var p in sortedSource)
            {
                var item = allItems.Where(i => predicate(i, p)).ToList();
                if (!item.IsNullOrEmpty())
                    temp.AddRange(item);
                allItems = allItems.Except(item).ToList();
            }
            if (!allItems.IsNullOrEmpty())
                temp.AddRange(allItems);
            return temp;
        }
    }
}
